home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / shadow-9.tar / shadow-9 / shadow-960129 / lmain.c < prev    next >
C/C++ Source or Header  |  1995-12-17  |  23KB  |  1,018 lines

  1. /*
  2.  * Copyright 1989 - 1994, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by John F. Haugh, II
  16.  *      and other contributors.
  17.  * 4. Neither the name of John F. Haugh, II nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY JOHN HAUGH AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL JOHN HAUGH OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef    lint
  35. static char rcsid[] = "$Id: lmain.c,v 1.3 1995/12/17 03:50:36 marekm Exp $";
  36. #endif
  37.  
  38. #include "config.h"
  39. #include "prototypes.h"
  40. #include "defines.h"
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #include <stdio.h>
  44. #include "pwd.h"
  45. #include <grp.h>
  46. #ifdef SVR4
  47. #include <utmpx.h>
  48. #else
  49. #include <utmp.h>
  50. #endif
  51. #include <time.h>
  52. #include <signal.h>
  53. #ifndef    BSD
  54. #if defined(SVR4) || defined(__linux__)
  55. #include <termios.h>
  56. #else    /* !SVR4 */
  57. #include <termio.h>
  58. #endif    /* SVR4 */
  59. #else
  60. #include <sgtty.h>
  61. #endif
  62.  
  63. #ifdef HAVE_RLIMIT
  64. #include <sys/resource.h>
  65. #endif
  66.  
  67. #include "lastlog.h"
  68. #include "faillog.h"
  69. #ifdef    SHADOWPWD
  70. #include "shadow.h"
  71. #endif
  72. #include "pwauth.h"
  73.  
  74. #ifdef SVR4_SI86_EUA
  75. #include <sys/proc.h>
  76. #include <sys/sysi86.h>
  77. #endif
  78.  
  79. #ifdef    USE_SYSLOG
  80. #include <syslog.h>
  81.  
  82. #ifndef    LOG_WARN
  83. #define    LOG_WARN    LOG_WARNING
  84. #endif
  85. #endif
  86.  
  87. #if defined(RLOGIN) || defined(UT_HOST) || defined(SVR4)
  88. char    host[BUFSIZ];
  89. #ifndef NO_RFLG
  90. char    term[128] = "TERM=";
  91. int    remote_speed = 9600;
  92. #endif
  93. #endif
  94.  
  95. #ifndef LOGIN_PROMPT
  96. #define LOGIN_PROMPT "login: "
  97. #endif
  98.  
  99. struct    passwd    pwent;
  100. #ifdef SVR4
  101. struct    utmpx    utxent, failent;
  102. struct    utmp    utent;
  103. #else    /*!SVR4 */
  104. struct    utmp    utent, failent;
  105. #endif    /* SVR4 */
  106. struct    lastlog    lastlog;
  107. int    pflg;
  108. int    fflg;
  109. #if defined(RLOGIN) && !defined(NO_RFLG)
  110. int    rflg;
  111. #else
  112. #define rflg 0
  113. #endif
  114. #ifdef    RLOGIN
  115. int    hflg;
  116. #else
  117. #define hflg 0
  118. #endif
  119. int    preauth_flag;
  120.  
  121. #if defined(SVR4) || defined(SUN4) || defined(__linux__)
  122. #define    STTY(fd,termio) tcsetattr (fd, TCSANOW, termio)
  123. #define    GTTY(fd,termio) tcgetattr (fd, termio)
  124. #define    TERMIO    struct    termios
  125. #else
  126. #ifndef BSD
  127. #define    STTY(fd,termio) ioctl(fd, TCSETA, termio)
  128. #define    GTTY(fd,termio) ioctl(fd, TCGETA, termio)
  129. #define    TERMIO    struct    termio
  130. #else    /* BSD */
  131. #define    STTY(fd,termio) stty(fd, termio)
  132. #define    GTTY(fd,termio) gtty(fd, termio)
  133. #endif    /* !BSD */
  134. #endif    /* SVR4 || SUN4 */
  135. TERMIO    termio;
  136.  
  137. #ifndef    MAXENV
  138. #define    MAXENV    64
  139. #endif
  140.  
  141. /*
  142.  * Global variables.
  143.  */
  144.  
  145. char    *newenvp[MAXENV];
  146. char    *Prog;
  147. int    newenvc = 0;
  148. int    maxenv = MAXENV;
  149.  
  150. /*
  151.  * External identifiers.
  152.  */
  153.  
  154. extern    char    *getenv ();
  155. extern    char    *tz ();
  156. extern    void    checkutmp ();
  157. extern    void    addenv ();
  158. extern    void    set_env ();
  159. extern    unsigned alarm ();
  160. extern    void    login ();
  161. extern    void    setutmp ();
  162. extern    void    subsystem ();
  163. extern    void    log ();
  164. extern    void    setup ();
  165. extern    int    expire ();
  166. extern    void    motd ();
  167. extern    void    mailcheck ();
  168. extern    void    shell ();
  169. extern    long    a64l ();
  170. extern    int    c64i ();
  171. extern    char    *getdef_str();
  172. extern    int    getdef_bool();
  173. extern    int    getdef_num();
  174. extern    long    getdef_long();
  175. extern    int    optind;
  176. extern    char    *optarg;
  177. extern    char    **environ;
  178. extern    int    pw_auth();
  179.  
  180. #ifdef HAVE_ULIMIT
  181. extern    long    ulimit();
  182. #endif
  183.  
  184. #ifndef    ALARM
  185. #define    ALARM    60
  186. #endif
  187.  
  188. #ifndef    RETRIES
  189. #define    RETRIES    3
  190. #endif
  191.  
  192. struct    faillog    faillog;
  193.  
  194. #define    NO_SHADOW    "no shadow password for `%s' on `%s'\n"
  195. #define    BAD_PASSWD_HOST    "invalid password for `%s' on `%s' from `%s'\n"
  196. #define    BAD_PASSWD    "invalid password for `%s' on `%s'\n"
  197. #define    BAD_DIALUP    "invalid dialup password for `%s' on `%s'\n"
  198. #define    BAD_TIME_HOST    "invalid login time for `%s' on `%s' from `%s'\n"
  199. #define    BAD_TIME    "invalid login time for `%s' on `%s'\n"
  200. #define    BAD_ROOT_LOGIN    "ILLEGAL ROOT LOGIN ON TTY `%s'\n"
  201. #define    ROOT_LOGIN    "ROOT LOGIN ON TTY `%s'\n"
  202. #define    FAILURE_CNT    "exceeded failure limit for `%s' on `%s'\n"
  203. #define    NOT_A_TTY    "not a tty\n"
  204. #define    NOT_ROOT    "-r or -f flag and not ROOT on `%s'\n"
  205. #define AUTHFAIL    "authentication failed for user `%s'\n"
  206.  
  207. /*
  208.  * usage - print login command usage and exit
  209.  *
  210.  * login [ name ]
  211.  * login -r hostname    (for rlogind)
  212.  * login -h hostname    (for telnetd, etc.)
  213.  * login -f name    (for pre-authenticated login: datakit, xterm, etc.)
  214.  */
  215.  
  216. void
  217. usage ()
  218. {
  219.     fprintf (stderr, "usage: login [ -p ] [ name ]\n");
  220. #ifdef    RLOGIN
  221. #ifndef NO_RFLG
  222.     fprintf (stderr, "       login [ -p ] -r name\n");
  223. #endif
  224.     fprintf (stderr, "       login [ -p ] [ -f name ] -h host\n");
  225. #else
  226.     fprintf (stderr, "       login [ -p ] -f name\n");
  227. #endif    /* RLOGIN */
  228.     exit (1);
  229. }
  230.  
  231. #if defined(RLOGIN) && !defined(NO_RFLG)
  232. struct    {
  233.     int    spd_name;
  234.     int    spd_baud;
  235. } speed_table [] = {
  236. #ifdef    B50
  237.     B50, 50,
  238. #endif
  239. #ifdef    B75
  240.     B75, 75,
  241. #endif
  242. #ifdef    B110
  243.     B110, 110,
  244. #endif
  245. #ifdef    B134
  246.     B134, 134,
  247. #endif
  248. #ifdef    B150
  249.     B150, 150,
  250. #endif
  251. #ifdef    B200
  252.     B200, 200,
  253. #endif
  254. #ifdef    B300
  255.     B300, 300,
  256. #endif
  257. #ifdef    B600
  258.     B600, 600,
  259. #endif
  260. #ifdef    B1200
  261.     B1200, 1200,
  262. #endif
  263. #ifdef    B1800
  264.     B1800, 1800,
  265. #endif
  266. #ifdef    B2400
  267.     B2400, 2400,
  268. #endif
  269. #ifdef    B4800
  270.     B4800, 4800,
  271. #endif
  272. #ifdef    B9600
  273.     B9600, 9600,
  274. #endif
  275. #ifdef    B19200
  276.     B19200, 19200,
  277. #endif
  278. #ifdef    B38400
  279.     B38400, 38400,
  280. #endif
  281.     -1,    -1
  282. };
  283.  
  284. rlogin (remote_host, name, namelen)
  285. char    *remote_host;
  286. char    *name;
  287. int    namelen;
  288. {
  289.     struct    passwd    *pwd;
  290.     char    remote_name[32];
  291.     char    *cp;
  292.     int    remote_speed = 9600;
  293.     int    speed_name = B9600;
  294.     int    i;
  295.  
  296.     get_remote_string (remote_name, sizeof remote_name);
  297.     get_remote_string (name, namelen);
  298.     get_remote_string (term + 5, sizeof term - 5);
  299.  
  300.     if (cp = strchr (term, '/')) {
  301.         *cp++ = '\0';
  302.  
  303.         if (! (remote_speed = atoi (cp)))
  304.             remote_speed = 9600;
  305.     }
  306.     for (i = 0;speed_table[i].spd_baud != remote_speed &&
  307.                 speed_table[i].spd_name != -1;i++)
  308.         ;
  309.  
  310.     if (speed_table[i].spd_name != -1)
  311.         speed_name = speed_table[i].spd_name;
  312.  
  313.     /*
  314.      * Put the terminal in cooked mode with echo turned on.
  315.      */
  316.  
  317.     GTTY (0, &termio);
  318. #ifndef    BSD
  319.     termio.c_iflag |= ICRNL|IXON;
  320.     termio.c_oflag |= OPOST|ONLCR;
  321.     termio.c_lflag |= ICANON|ECHO|ECHOE;
  322.     termio.c_cflag = (termio.c_cflag & ~CBAUD) | speed_name;
  323. #else
  324. #endif
  325.     STTY (0, &termio);
  326.  
  327.     if (! (pwd = getpwnam (name)))
  328.         return 0;
  329.  
  330.     /*
  331.      * ruserok() returns 0 for success on modern systems, and 1 on
  332.      * older ones.  If you are having trouble with people logging
  333.      * in without giving a required password, THIS is the culprit -
  334.      * go fix the #define in config.h.
  335.      */
  336.  
  337. #ifndef    RUSEROK
  338.     return 0;
  339. #else
  340.     return ruserok (remote_host, pwd->pw_uid == 0,
  341.                 remote_name, name) == RUSEROK;
  342. #endif
  343. }
  344.  
  345. get_remote_string (buf, size)
  346. char    *buf;
  347. int    size;
  348. {
  349.     for (;;) {
  350.         if (read (0, buf, 1) != 1)
  351.               exit (1);
  352.         if (*buf == '\0')
  353.             return;
  354.         if (--size > 0)
  355.             ++buf;
  356.     }
  357.     /*NOTREACHED*/
  358. }
  359. #endif
  360.  
  361. /*
  362.  * login - create a new login session for a user
  363.  *
  364.  *    login is typically called by getty as the second step of a
  365.  *    new user session.  getty is responsible for setting the line
  366.  *    characteristics to a reasonable set of values and getting
  367.  *    the name of the user to be logged in.  login may also be
  368.  *    called to create a new user session on a pty for a variety
  369.  *    of reasons, such as X servers or network logins.
  370.  *
  371.  *    the flags which login supports are
  372.  *    
  373.  *    -p - preserve the environment
  374.  *    -r - perform autologin protocol for rlogin
  375.  *    -f - do not perform authentication, user is preauthenticated
  376.  *    -h - the name of the remote host
  377.  */
  378.  
  379. int
  380. main (argc, argv, envp)
  381. int    argc;
  382. char    **argv;
  383. char    **envp;
  384. {
  385.     char    name[32];
  386.     char    tty[BUFSIZ];
  387.     int    reason = PW_LOGIN;
  388.     int    retries;
  389.     int    arg;
  390.     int    failed;
  391.     int    flag;
  392.     int    subroot = 0;
  393.     char    *fname;
  394.     char    *cp;
  395.     char    *tmp;
  396.     char    buff[128];
  397.     struct    passwd    *pwd;
  398. #ifdef    SHADOWPWD
  399.     struct    spwd    *spwd=NULL;
  400.     struct    spwd    *getspnam();
  401. #endif
  402.  
  403.     /*
  404.      * Some quick initialization.
  405.      */
  406.  
  407.     name[0] = '\0';
  408.  
  409.     /*
  410.      * Check the flags for proper form.  Every argument starting with
  411.      * "-" must be exactly two characters long.  This closes all the
  412.      * clever rlogin, telnet, and getty holes.
  413.      */
  414.  
  415.     for (arg = 1;arg < argc;arg++) {
  416.         if (argv[arg][0] == '-' && strlen (argv[arg]) > 2)
  417.             usage ();
  418.     }
  419.  
  420.     Prog = basename(argv[0]);
  421.  
  422. #ifdef RLOGIN
  423. #ifndef NO_RFLG
  424. #define FLAGS "pr:f:h:"
  425. #else
  426. #define FLAGS "pf:h:"
  427. #endif
  428. #else
  429. #define FLAGS "pf:"
  430. #endif
  431.     while ((flag = getopt (argc, argv, FLAGS)) != EOF)
  432. #undef FLAGS
  433.     {
  434.         switch (flag) {
  435.             case 'p': pflg++;
  436.                 break;
  437.             case 'f':
  438.                 fflg++;
  439.                 STRFCPY (name, optarg);
  440.                 break;
  441. #ifdef    RLOGIN
  442. #ifndef NO_RFLG
  443.             case 'r':
  444.                 rflg++;
  445.                 reason = PW_RLOGIN;
  446.                 STRFCPY (host, optarg);
  447.                 break;
  448. #endif
  449.             case 'h':
  450.                 hflg++;
  451.                 reason = PW_TELNET;
  452.                 STRFCPY (host, optarg);
  453.                 break;
  454. #endif    /*RLOGIN*/
  455.             default:
  456.                 usage ();
  457.         }
  458.     }
  459.  
  460. #if defined(RLOGIN) && !defined(NO_RFLG)
  461.     /*
  462.      * Neither -h nor -f should be combined with -r.
  463.      */
  464.  
  465.     if (rflg && (hflg || fflg))
  466.         usage ();
  467. #endif
  468.  
  469.     /*
  470.      * Allow authentication bypass only if real UID is zero.
  471.      */
  472.  
  473.     if ((rflg || fflg || hflg) && getuid () != 0) {
  474.         fprintf(stderr, "%s: permission denied\n", Prog);
  475.         exit (1);
  476.     }
  477.  
  478.     if (! isatty (0) || ! isatty (1) || ! isatty (2))
  479.         exit (1);        /* must be a terminal */
  480.  
  481.     /*
  482.      * Get the utmp file entry and get the tty name from it.  The
  483.      * current process ID must match the process ID in the utmp
  484.      * file if there are no additional flags on the command line.
  485.      */
  486.  
  487.     checkutmp (!rflg && !fflg && !hflg);
  488.     STRFCPY (tty, utent.ut_line);
  489.  
  490. #ifdef RLOGIN
  491.     if (rflg || hflg) {
  492. #ifdef    UT_HOST
  493.         STRFCPY (utent.ut_host, host);
  494. #endif    /*UT_HOST*/
  495. #ifdef    SVR4
  496.         STRFCPY (utxent.ut_host, host);
  497. #endif    /* SVR4 */
  498.     }
  499.     if (hflg && fflg) {
  500.         reason = PW_RLOGIN;
  501.         preauth_flag++;
  502.     }
  503. #ifndef NO_RFLG
  504.     if (rflg && rlogin (host, name, sizeof name))
  505.         preauth_flag++;
  506. #endif
  507. #endif  /* RLOGIN */
  508.  
  509. #ifdef    USE_SYSLOG
  510.     openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  511. #endif
  512.  
  513.     GTTY (0, &termio);        /* get terminal characteristics */
  514.  
  515.  
  516.     /*
  517.      * Add your favorite terminal modes here ...
  518.      */
  519.  
  520. #ifndef    BSD
  521.     termio.c_lflag |= ISIG|ICANON|ECHO|ECHOE;
  522.     termio.c_iflag |= ICRNL;
  523.  
  524. #if defined(ECHOKE) && defined(ECHOCTL)
  525.     termio.c_lflag |= ECHOKE|ECHOCTL;
  526. #endif
  527. #if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
  528.     termio.c_lflag &= ~(ECHOPRT|NOFLSH|TOSTOP);
  529. #endif
  530. #ifdef    ONLCR
  531.     termio.c_oflag |= ONLCR;
  532. #endif
  533.  
  534. #ifdef    SUN4
  535.  
  536.     /*
  537.      * Terminal setup for SunOS 4.1 courtesy of Steve Allen
  538.      * at UCO/Lick.
  539.      */
  540.  
  541.     termio.c_cc[VEOF] = '\04';
  542.     termio.c_cflag &= ~CSIZE;
  543.     termio.c_cflag |= (PARENB|CS7);
  544.     termio.c_lflag |= (ISIG|ICANON|ECHO|IEXTEN);
  545.     termio.c_iflag |= (BRKINT|IGNPAG|ISTRIP|IMAXBEL|ICRNL|IXON);
  546.     termio.c_iflag &= ~IXANY;
  547.     termio.c_oflag |= (XTABS|OPOST|ONLCR);
  548. #endif
  549.     termio.c_cc[VERASE] = getdef_num("ERASECHAR", '\b');
  550.     termio.c_cc[VKILL] = getdef_num("KILLCHAR", '\025');
  551.  
  552.     /*
  553.      * ttymon invocation prefers this, but these settings won't come into
  554.      * effect after the first username login 
  555.      */
  556.  
  557. #else
  558. #endif    /* !BSD */
  559.     STTY (0, &termio);
  560.  
  561.     umask (getdef_num("UMASK", 077));
  562.  
  563. #if defined(HAVE_ULIMIT) || defined(HAVE_RLIMIT)
  564.     {
  565.         /* 
  566.          * Use the ULIMIT in the login.defs file, and if
  567.          * there isn't one, use the default value.  The
  568.          * user may have one for themselves, but otherwise,
  569.          * just take what you get.
  570.          */
  571.  
  572.         long limit = getdef_long("ULIMIT", -1L);
  573.  
  574.         if (limit != -1) {
  575. #ifndef HAVE_ULIMIT
  576.             struct rlimit rlimit_fsize;
  577.  
  578.             bzero(&rlimit_fsize, sizeof rlimit_fsize);
  579.             rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max =
  580.                 limit * 512;
  581.             setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
  582. #else
  583.             ulimit (2, limit);
  584. #endif
  585.         }
  586.     }
  587. #endif
  588.  
  589.     /*
  590.      * The entire environment will be preserved if the -p flag
  591.      * is used.
  592.      */
  593.  
  594.     if (pflg)
  595.         while (*envp)        /* add inherited environment, */
  596.             addenv (*envp++); /* some variables change later */
  597.  
  598. #if defined(RLOGIN) && !defined(NO_RFLG)
  599.     if (term[5] != '\0')        /* see if anything after "TERM=" */
  600.         addenv (term);
  601.     else
  602. #endif
  603.     if (!pflg && (tmp = getenv("TERM")) && strlen(tmp)+5 < sizeof buff) {
  604.         /* preserve TERM from getty */
  605.         strcpy(buff, "TERM=");
  606.         strcat(buff, tmp);
  607.         addenv(buff);
  608.     }
  609.     /*
  610.      * Add the timezone environmental variable so that time functions
  611.      * work correctly.
  612.      */
  613.  
  614.     if ((tmp = getenv ("TZ"))) {
  615.         if (strlen(tmp)+3 < sizeof buff) {
  616.             strcpy(buff, "TZ=");
  617.             strcat(buff, tmp);
  618.             addenv(buff);
  619.         }
  620.     } else if ((cp = getdef_str ("ENV_TZ")))
  621.         addenv (*cp == '/' ? tz (cp):cp);
  622.  
  623.     /* 
  624.      * Add the clock frequency so that profiling commands work
  625.      * correctly.
  626.      */
  627.  
  628.     if ((tmp = getenv("HZ"))) {
  629.         if (strlen(tmp)+3 < sizeof buff) {
  630.             strcpy(buff, "HZ=");
  631.             strcat(buff, tmp);
  632.             addenv(buff);
  633.         }
  634.     } else if ((cp = getdef_str("ENV_HZ")))
  635.         addenv (cp);
  636.  
  637.     if (optind < argc) {        /* get the user name */
  638.         if (rflg || fflg)
  639.             usage ();
  640.  
  641. #ifdef SVR4
  642.         /*
  643.          * The "-h" option can't be used with a command-line username,
  644.          * because telnetd invokes us as: login -h host TERM=...
  645.          */
  646.  
  647.         if (! hflg) {
  648.             STRFCPY (name, argv[optind]);
  649.             ++optind;
  650.         }
  651. #else
  652.         STRFCPY (name, argv[optind]);
  653.         ++optind;
  654. #endif
  655.     }
  656. #ifdef SVR4
  657.     /*
  658.      * check whether ttymon has done the prompt for us already
  659.      */
  660.  
  661.     {
  662.         char *ttymon_prompt;
  663.  
  664.         if ((ttymon_prompt = getenv("TTYPROMPT")) != NULL &&
  665.             (*ttymon_prompt != 0)) {
  666.         login(name, 0);    /* read name, without prompt */
  667.         }
  668.     }
  669. #endif /* SVR4 */
  670.     if (optind < argc)        /* now set command line variables */
  671.             set_env (argc - optind, &argv[optind]);
  672.  
  673. top:
  674.     /* only allow ALARM sec. for login */
  675.     alarm(getdef_num("LOGIN_TIMEOUT", ALARM));
  676.  
  677.     environ = newenvp;        /* make new environment active */
  678.     retries = getdef_num("LOGIN_RETRIES", RETRIES);
  679.     while (1) {    /* repeatedly get login/password pairs */
  680.         failed = 0;        /* haven't failed authentication yet */
  681.  
  682.         if (! name[0]) {    /* need to get a login id */
  683.             if (subroot) {
  684. #ifdef    USE_SYSLOG
  685.                 closelog ();
  686. #endif
  687.                 exit (1);
  688.             }
  689. #ifdef    RLOGIN
  690.             preauth_flag = 0;
  691. #endif
  692.             login (name, LOGIN_PROMPT);
  693.             continue;
  694.         }
  695.         if (! (pwd = getpwnam (name))) {
  696.             pwent.pw_name = name;
  697.             pwent.pw_passwd = "!";
  698.             pwent.pw_shell = "/bin/sh";
  699.  
  700.             preauth_flag = 0;
  701.             failed = 1;
  702.         } else {
  703.             pwent = *pwd;
  704.         }
  705. #ifdef    SHADOWPWD
  706.         if (pwd) {
  707.             if (! (spwd = getspnam (name)))
  708. #ifdef    USE_SYSLOG
  709.                 syslog (LOG_WARN, NO_SHADOW, name, tty);
  710. #else
  711.                 ;
  712. #endif
  713.             else
  714.                 pwent.pw_passwd = spwd->sp_pwdp;
  715.         }
  716. #endif    /* SHADOWPWD */
  717. #ifdef    RLOGIN
  718.         /*
  719.          * If the encrypted password begins with a "!", the account
  720.          * is locked and the user cannot login, even if they have
  721.          * been "pre-authenticated."
  722.          */
  723.  
  724.         if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
  725.             failed = 1;
  726.  
  727.         /*
  728.          * The -r and -f flags provide a name which has already
  729.          * been authenticated by some server.
  730.          */
  731.  
  732.         if (preauth_flag)
  733.             goto have_name;
  734. #endif    /*RLOGIN*/
  735.  
  736.         if (pw_auth (pwent.pw_passwd, name, reason, (char *) 0)) {
  737. #ifdef    USE_SYSLOG
  738. #ifdef UT_HOST
  739.             if (*(utent.ut_host))
  740.                 syslog (LOG_WARN, BAD_PASSWD_HOST,
  741.                     name, tty, utent.ut_host);
  742.             else
  743. #endif /* UT_HOST */
  744. #ifdef SVR4
  745.             if (*(utxent.ut_host))
  746.                 syslog (LOG_WARN, BAD_PASSWD_HOST,
  747.                     name, tty, utxent.ut_host);
  748.             else
  749. #endif /* SVR4 */
  750.                 syslog (LOG_WARN, BAD_PASSWD,
  751.                     name, tty);
  752. #endif /* USE_SYSLOG */
  753.             failed = 1;
  754.         }
  755.         goto auth_done;
  756.  
  757.         /*
  758.          * This is the point where all authenticated users
  759.          * wind up.  If you reach this far, your password has
  760.          * been authenticated and so on.
  761.          */
  762.  
  763. auth_done:
  764. #ifdef    RLOGIN
  765. have_name:
  766. #endif
  767.         if (getdef_bool("DIALUPS_CHECK_ENAB")) {
  768.             alarm (30);
  769.  
  770.             if (! dialcheck (tty, pwent.pw_shell[0] ?
  771.                     pwent.pw_shell:"/bin/sh")) {
  772. #ifdef    USE_SYSLOG
  773.                 syslog (LOG_WARN, BAD_DIALUP, name, tty);
  774. #endif
  775.                 failed = 1;
  776.             }
  777.         }
  778.         if (getdef_bool("PORTTIME_CHECKS_ENAB") &&
  779.             ! isttytime (pwent.pw_name, tty, time ((time_t *) 0))
  780.         ) {
  781. #ifdef    USE_SYSLOG
  782. #ifdef UT_HOST
  783.             if (*(utent.ut_host))
  784.                 syslog (LOG_WARN, BAD_TIME_HOST, name, tty,
  785.                     utent.ut_host);
  786.             else
  787. #endif    /* UT_HOST */
  788. #ifdef SVR4
  789.             if (*(utxent.ut_host))
  790.                 syslog (LOG_WARN, BAD_TIME_HOST, name, tty,
  791.                     utxent.ut_host);
  792.             else
  793. #endif    /* SVR4 */
  794.                 syslog (LOG_WARN, BAD_TIME, name, tty);
  795. #endif    /* USE_SYSLOG */
  796.                 failed = 1;
  797.         }
  798.         if (! failed && pwent.pw_name && pwent.pw_uid == 0 &&
  799.                 ! console (tty)) {
  800. #ifdef    USE_SYSLOG
  801.             syslog (LOG_CRIT, BAD_ROOT_LOGIN, tty);
  802. #endif
  803.             failed = 1;
  804.         }
  805.         if (pwd && getdef_bool("FAILLOG_ENAB") && 
  806.                 ! failcheck (pwent.pw_uid, &faillog, failed)) {
  807. #ifdef    USE_SYSLOG
  808.             syslog (LOG_CRIT, FAILURE_CNT, name, tty);
  809. #endif
  810.             failed = 1;
  811.         }
  812.         if (! failed)
  813.             break;
  814.  
  815.         /* don't log non-existent users */
  816.         if (pwd && getdef_bool("FAILLOG_ENAB"))
  817.             failure (pwent.pw_uid, tty, &faillog);
  818.         if (getdef_str("FTMP_FILE") != NULL) {
  819. #ifdef    SVR4
  820.             failent = utxent;
  821. #else
  822.             failent = utent;
  823. #endif
  824.  
  825.             if (pwd)
  826.                 STRFCPY (failent.ut_name, pwent.pw_name);
  827.             else
  828.                 if (getdef_bool("LOG_UNKFAIL_ENAB"))
  829.                     STRFCPY (failent.ut_name, name);
  830.                 else
  831.                     STRFCPY (failent.ut_name, "UNKNOWN");
  832. #ifdef    SVR4
  833.             gettimeofday (&(failent.ut_tv));
  834. #else
  835.             time (&failent.ut_time);
  836. #endif
  837. #ifdef    USG_UTMP
  838.             failent.ut_type = USER_PROCESS;
  839. #endif
  840.             failtmp (&failent);
  841.         }
  842.  
  843.         /*
  844.          * Wait a while (a la SVR4 /usr/bin/login) before attempting
  845.          * to login the user again.  If the earlier alarm occurs
  846.          * before the sleep() below completes, login will exit.
  847.          */
  848.  
  849.         /* Moved it here - Solaris 2.3 at least prints the message
  850.            after the delay, not the other way around.  If the cracker
  851.            gets "Login incorrect" immediately, they may disconnect
  852.            quickly and connect again , defeating the purpose of the
  853.            delay (slow down password guessing attempts).  --marekm */
  854.  
  855.         if (getdef_num ("FAIL_DELAY", 0))
  856.             sleep (getdef_num ("FAIL_DELAY", 0));
  857.  
  858.         puts ("Login incorrect");
  859.  
  860. #ifdef    RLOGIN
  861.         if (rflg || fflg) {
  862. #ifdef    USE_SYSLOG
  863.             closelog ();
  864. #endif
  865.             exit (1);
  866.         }
  867. #endif    /*RLOGIN*/
  868.  
  869.         if (--retries <= 0) {    /* only allow so many failures */
  870. #ifdef    USE_SYSLOG
  871.             closelog ();
  872. #endif
  873.             exit (1);
  874.         }
  875.         bzero (name, sizeof name);
  876.     }
  877.     (void) alarm (0);        /* turn off alarm clock */
  878.  
  879.     /*
  880.      * Check to see if system is turned off for non-root users.
  881.      * This would be useful to prevent users from logging in
  882.      * during system maintenance.  We make sure the message comes
  883.      * out for root so she knows to remove the file if she's
  884.      * forgotten about it ...
  885.      */
  886.  
  887.     fname = getdef_str("NOLOGINS_FILE");
  888.     if (fname != NULL && access (fname, 0) == 0) {
  889.         FILE    *nlfp;
  890.         int    c;
  891.  
  892.         /*
  893.          * Cat the file if it can be opened, otherwise just
  894.          * print a default message
  895.          */
  896.  
  897.         if ((nlfp = fopen (fname, "r"))) {
  898.             while ((c = getc (nlfp)) != EOF) {
  899.                 if (c == '\n')
  900.                     putchar ('\r');
  901.  
  902.                 putchar (c);
  903.             }
  904.             fflush (stdout);
  905.             fclose (nlfp);
  906.         } else
  907.             printf ("\r\nSystem closed for routine maintenance\r\n");
  908.         /*
  909.          * Non-root users must exit.  Root gets the message, but
  910.          * gets to login.
  911.          */
  912.  
  913.         if (pwent.pw_uid != 0) {
  914.   
  915. #ifdef    USE_SYSLOG
  916.             closelog ();
  917. #endif
  918.             exit (0);
  919.         }
  920.         printf ("\r\n[Disconnect bypassed -- root login allowed.]\r\n");
  921.     }
  922.     if (getenv ("IFS"))        /* don't export user IFS ... */
  923.         addenv ("IFS= \t\n");    /* ... instead, set a safe IFS */
  924.  
  925.     setutmp (name, tty);        /* make entry in utmp & wtmp files */
  926.     if (pwent.pw_shell[0] == '*') {    /* subsystem root */
  927.         subsystem (&pwent);    /* figure out what to execute */
  928.         subroot++;        /* say i was here again */
  929.         endpwent ();        /* close all of the file which were */
  930.         endgrent ();        /* open in the original rooted file */
  931. #ifdef    SHADOWPWD
  932.         endspent ();        /* system.  they will be re-opened */
  933. #endif
  934. #ifdef    SHADOWGRP
  935.         endsgent ();        /* in the new rooted file system */
  936. #endif
  937.         goto top;        /* go do all this all over again */
  938.     }
  939.     if (getdef_bool("LASTLOG_ENAB"))
  940.         log ();            /* give last login and log this one */
  941.  
  942. #ifdef SVR4_SI86_EUA
  943.     sysi86(SI86LIMUSER, EUA_ADD_USER);    /* how do we test for fail? */
  944. #endif
  945.  
  946.     setup (&pwent);            /* set UID, GID, HOME, etc ... */
  947. #ifdef    AGING
  948. #ifdef    SHADOWPWD
  949.     if (spwd) {            /* check for age of password */
  950.         if (expire (&pwent, spwd)) {
  951.             spwd = getspnam (name);
  952.             pwd = getpwnam (name);
  953.             pwent = *pwd;
  954.         }
  955.     }
  956. #endif
  957. #ifdef    ATT_AGE
  958. #ifdef    SHADOWPWD
  959.     else
  960. #endif
  961.     if (pwent.pw_age && pwent.pw_age[0]) {
  962.         if (expire (&pwent)) {
  963.             pwd = getpwnam (name);
  964.             pwent = *pwd;
  965.         }
  966.     }
  967. #endif    /* ATT_AGE */
  968. #endif    /* AGING */
  969.     if (! hushed (&pwent)) {
  970.         motd ();        /* print the message of the day */
  971.         if (getdef_bool ("FAILLOG_ENAB") && faillog.fail_cnt != 0)
  972.             failprint (&faillog);
  973.         if (getdef_bool ("LASTLOG_ENAB") && lastlog.ll_time != 0) {
  974.             printf ("Last login: %.19s on %s",
  975.                 ctime (&lastlog.ll_time), lastlog.ll_line);
  976. #if defined(SVR4) || defined(__linux__) || defined(SUN4)
  977.             if (lastlog.ll_host[0])
  978.                 printf(" from %.16s", lastlog.ll_host);
  979. #endif
  980.             printf(".\n");
  981.         }
  982. #ifdef    AGING
  983. #ifdef    SHADOWPWD
  984.         agecheck (&pwent, spwd);
  985. #else
  986.         agecheck (&pwent);
  987. #endif
  988. #endif    /* AGING */
  989.         mailcheck ();    /* report on the status of mail */
  990.     }
  991.     if (getdef_str("TTYTYPE_FILE") != NULL && getenv("TERM") == NULL)
  992.           ttytype (tty);
  993.  
  994.     signal (SIGINT, SIG_DFL);    /* default interrupt signal */
  995.     signal (SIGQUIT, SIG_DFL);    /* default quit signal */
  996.     signal (SIGTERM, SIG_DFL);    /* default terminate signal */
  997.     signal (SIGALRM, SIG_DFL);    /* default alarm signal */
  998.     signal (SIGHUP, SIG_DFL);    /* added this.  --marekm */
  999.  
  1000.     endpwent ();            /* stop access to password file */
  1001.     endgrent ();            /* stop access to group file */
  1002. #ifdef    SHADOWPWD
  1003.     endspent ();            /* stop access to shadow passwd file */
  1004. #endif
  1005. #ifdef    SHADOWGRP
  1006.     endsgent ();            /* stop access to shadow group file */
  1007. #endif
  1008. #ifdef    USE_SYSLOG
  1009.     if (pwent.pw_uid == 0)
  1010.         syslog (LOG_NOTICE, ROOT_LOGIN, tty);
  1011.  
  1012.     closelog ();
  1013. #endif
  1014.     shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
  1015.     /*NOTREACHED*/
  1016.     return (0);
  1017. }
  1018.